﻿using UnityEngine;
using System;
using UniRx;

public partial class Timer
{
    /// <summary>
    /// 提供两段计时，提供 开始、结束、更新、归一化事件
    /// </summary>
    public class DoubleStage
    {
        /// <summary>
        /// 计时器开始
        /// </summary>
        public IObservable<Unit> onStart => onTimerStart;

        /// <summary>
        /// 一阶段结束
        /// </summary>
        public IObservable<Unit> onFinish_1 => onTimerEnd_1;

        /// <summary>
        /// 二阶段结束
        /// </summary>
        public IObservable<Unit> onFinish_2 => onTimerEnd_2;

        /// <summary>
        /// 计时器被从外部中断
        /// </summary>
        public IObservable<Unit> onShutDown => onShutdown;

        /// <summary>
        /// 计时器更新，已运行时间
        /// </summary>
        public IObservable<float> onUpdate => runTime;

        /// <summary>
        /// 一阶段进度归一化
        /// </summary>
        public IObservable<float> onNormalizedUpdate_1 => runTimeNormalized_1;

        /// <summary>
        /// 二阶段进度归一化
        /// </summary>
        public IObservable<float> onNormalizedUpdate_2 => runTimeNormalized_2;

        /// <summary>
        /// 总进度归一化
        /// </summary>
        public IObservable<float> onNormalizedUpdate_total => runTimeNormalized_total;

        /// <summary>
        /// 计时器是否还在运行
        /// </summary>
        public bool isRuning => time > 0;

        private Subject<Unit> onTimerStart = new Subject<Unit>();
        private Subject<Unit> onTimerEnd_1 = new Subject<Unit>();
        private Subject<Unit> onTimerEnd_2 = new Subject<Unit>();
        private Subject<Unit> onShutdown = new Subject<Unit>();
        private ReactiveProperty<float> runTime = new ReactiveProperty<float>();
        private ReactiveProperty<float> runTimeNormalized_1 = new ReactiveProperty<float>();
        private ReactiveProperty<float> runTimeNormalized_2 = new ReactiveProperty<float>();
        private ReactiveProperty<float> runTimeNormalized_total = new ReactiveProperty<float>();
        private IDisposable process = null;
        private bool hasNoticed_1 = false;
        private float time = -1f;

        /// <summary>
        /// 开始计时，gameobject未激活时暂停计时
        /// </summary>
        public void Start(float countTime_1, float countTime_2, MonoBehaviour owner = null)
        {
            time = 0f;
            hasNoticed_1 = false;
            onTimerStart.OnNext(Unit.Default);
            process?.Dispose();
            process = Observable.EveryLateUpdate().Where(_ => owner == null || owner.gameObject.activeInHierarchy).Subscribe(_ =>
            {
                if (time < 0)
                {
                    process.Dispose();
                }
                time += Time.deltaTime;
                runTime.Value = Mathf.Clamp(time, 0, countTime_1 + countTime_2);
                runTimeNormalized_1.Value = Mathf.Clamp(time / countTime_1, 0, 1f);
                runTimeNormalized_2.Value = Mathf.Clamp((time - countTime_1) / countTime_2, 0, 1f);
                runTimeNormalized_total.Value = Mathf.Clamp(time / (countTime_1 + countTime_2), 0, 1f);
                if (time > countTime_1 && !hasNoticed_1)
                {
                    hasNoticed_1 = true;
                    onTimerEnd_1.OnNext(Unit.Default);
                }
                if (time >= countTime_1 + countTime_2)
                {
                    time = -1f;
                    process.Dispose();
                    onTimerEnd_2.OnNext(Unit.Default);
                }
            });
        }

        /// <summary>
        /// 停止计时器
        /// </summary>
        public void ShutDown()
        {
            time = -1f;
            if (time > 0)
                onShutdown.OnNext(Unit.Default);
        }
    }
}